home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ue312src.zip / MSWMEM.C < prev    next >
C/C++ Source or Header  |  1992-10-15  |  11KB  |  391 lines

  1. /* The routines in this file provide memory allocation under the
  2.    Microsoft Windows environment on an IBM-PC or compatible computer.
  3.  
  4.    Must be compiled with Borland C++ 2.0 or later version.
  5.  
  6.    It should not be compiled if the WINDOW_MSWIN symbol is not set */
  7.  
  8. /* this module allocates memory by performing subsegment allocation from
  9.    a list of global segments. This technique is inspired by an article
  10.    by Paul Yao in Microsoft Systems Journal (January 1991) */
  11.  
  12. #include    "estruct.h"
  13. #include    <stdio.h>
  14. #include    "eproto.h"
  15. #include    "edef.h"
  16. #include    "elang.h"
  17.  
  18. #if    WINDOW_MSWIN
  19.  
  20. #include    "mswin.h"
  21.  
  22. #if SUBALLOC
  23. #ifdef  malloc
  24. #undef  malloc
  25. #endif
  26. #ifdef  free
  27. #undef  free
  28. #endif
  29. #ifdef  realloc
  30. #undef  realloc
  31. #endif
  32.  
  33. #define SEGHEADOFFSET 16    /* offset of the segment header (the first
  34.                    16 bytes of a heap segment are reserved
  35.                    for windows) */
  36. #define HEAPOFFSET  (SEGHEADOFFSET +  sizeof(SEGHEADER))
  37. #define HEAPOVH     0x400      /* estimated heap overhead */
  38. #define MINSEGSIZE  0x1000L /* minimum segment allocation: 4K */
  39.  
  40. /* Data segment switching macroes. The wS argument MUST be a stack
  41.    variable */
  42. #define SWITCH_DS(wS) asm {push ds; mov ax,wS; mov ds,ax;}
  43. #define RESTORE_DS    asm {pop ds;}
  44.  
  45. typedef struct  SegHeader {     /* segment header */
  46.     struct SegHeader *next;         /* link to next segment header */
  47.     int     alloc_count;            /* number of allocated blocks */
  48. } SEGHEADER;
  49.  
  50. static SEGHEADER SegList = {NULL, -1};/* list of segments (dummy header) */
  51. static SEGHEADER *OptimumSeg = NULL;
  52.  
  53. static BOOL FarStorage = FALSE; /* validates the use of suballocation */
  54.  
  55. #if MEMTRACE
  56. static  unsigned char mtrx = 0;
  57. static  struct mtr_tag {
  58.     WORD    m_func;         /* ASCII signature of function */
  59.     union   {
  60.         WORD    m_wseg;     /* segment selector */
  61.         void    *m_block;   /* block address */
  62.         SEGHEADER *m_segh;  /* segment header */
  63.     } m_ptr;
  64.     WORD    m_cnt;          /* alloc count */
  65.     DWORD   m_size;         /* size of segment or block */
  66.     SEGHEADER *m_optimseg;  /* value of OptimumSeg */
  67. } mtr [256];
  68.  
  69. /* m_func values ... */
  70. #define MTR_SUBALLOC    'SU'
  71. #define MTR_MALLOC      'MA'
  72. #define MTR_MALLOCSEG   'MS'
  73. #define MTR_FREE        'FR'
  74. #define MTR_FREESEG     'FS'
  75. #define MTR_REALLOC     'RA'
  76. #endif
  77.  
  78. /* SubAlloc:    performs suballocation from a global segment */
  79. /* ========                                                  */
  80.  
  81. void *SubAlloc(WORD wSeg, unsigned size)
  82.  
  83. /* wSeg is the global segment's selector */
  84. {
  85.     HANDLE  hBlock;     /* better be a stack variable */
  86.     void    *Block;     /* better be a stack variable */
  87. #if MEMTRACE
  88.     WORD    RealSize = 0;/* better be a stack variable */
  89. #endif
  90.     SWITCH_DS(wSeg)
  91.     hBlock = LocalAlloc (LMEM_FIXED | LMEM_NOCOMPACT, size);
  92.     /* no point attempting compaction: everything is FIXED
  93.        in this heap! */
  94.     if (hBlock) {
  95.     Block = (void*)(LPSTR)LocalLock (hBlock);
  96. #if MEMTRACE
  97.     RealSize = LocalSize (hBlock);
  98. #endif
  99.     }
  100.     RESTORE_DS
  101. #if MEMTRACE
  102.     mtr[mtrx].m_func = MTR_SUBALLOC;
  103.     mtr[mtrx].m_ptr.m_block = hBlock ? Block : NULL;
  104.     mtr[mtrx].m_size = RealSize;
  105.     mtr[mtrx++].m_optimseg = OptimumSeg;
  106. #endif
  107.     if (hBlock) return Block;       /* success ! */
  108.     else return NULL;               /* failure!! */
  109. } /* SubAlloc */
  110.  
  111. /* malloc:  allocates a chunk of memory */
  112. /* ======                               */
  113.  
  114. void * CDECL malloc(size_t size)
  115. {
  116.     SEGHEADER *Seg;         /* segment header pointer */
  117.     WORD    wSeg;           /* segment's selector, must be a stack variable */
  118.     BOOL    NewSeg = FALSE; /* TRUE: a new segment has been allocated */
  119.     void    *Block;         /* obtained block's address */
  120.  
  121. #if MEMTRACE
  122.     mtr[mtrx].m_func = MTR_MALLOC;
  123.     mtr[mtrx].m_ptr.m_block = NULL;
  124.     mtr[mtrx].m_size = size;
  125.     mtr[mtrx++].m_optimseg = OptimumSeg;
  126. #endif
  127.  
  128.     if (size == 0) return NULL;
  129.  
  130.     if (FarStorage == FALSE) {  /* use the local heap */
  131.     HANDLE hMem;
  132.  
  133.     if ((hMem = LocalAlloc (LMEM_FIXED, size)) != NULL) {
  134.         return (LPSTR)LocalLock (hMem);
  135.     }
  136.     else return NULL;
  137.     }
  138.  
  139.     /*-Attempt to suballocate from last used segment */
  140.     if (OptimumSeg) {
  141.     wSeg = HIWORD(OptimumSeg);
  142. #if MEMTRACE
  143.         mtr[mtrx].m_cnt = OptimumSeg->alloc_count;
  144. #endif
  145.     Block = SubAlloc (wSeg, size);
  146.     if (Block != NULL) {
  147.             ++(OptimumSeg->alloc_count);
  148.         return (char*)Block;     /* quick success ! */
  149.     }
  150.     }
  151.  
  152.     /*-Scan segment list, attempting to find one where suballocation is
  153.        possible */
  154.     Seg = &SegList;
  155.     for (;;) {
  156.     if (Seg->next == NULL) {
  157.         /*-initialize a new Segment and chain it on tail */
  158.         HANDLE      hSeg;
  159.         DWORD       SegSize;
  160.  
  161.         SegSize = max (MINSEGSIZE, HEAPOVH + SEGHEADOFFSET +
  162.                        sizeof(SEGHEADER) + (DWORD)size);
  163.         hSeg = GlobalAlloc (GMEM_MOVEABLE, SegSize);
  164.         if (hSeg == NULL) return (char*)NULL;  /* segment allocation
  165.                               failure */
  166.         SegSize = GlobalSize (hSeg);
  167.         wSeg = HIWORD(GlobalLock (hSeg));
  168.         LocalInit (wSeg, 0, SegSize - HEAPOFFSET);
  169.         GlobalUnlock (hSeg);
  170.         /* the segment remains locked once, due to LocalInit */
  171.  
  172.         SWITCH_DS(wSeg)
  173.         LockData (0);   /* this ensures the segment's selector will
  174.                    never change */
  175.         /* note that allocating a GMEM_FIXED segment would have been
  176.            cleaner but, in Windows 3.0, such segments also end up
  177.            being page-locked */
  178.         RESTORE_DS
  179.  
  180.         Seg->next = (SEGHEADER*)MAKELONG(SEGHEADOFFSET,wSeg);
  181.         Seg = Seg->next;
  182.         Seg->next = NULL;
  183.         Seg->alloc_count = 0;
  184.         NewSeg = TRUE;
  185. #if MEMTRACE
  186.     mtr[mtrx].m_func = MTR_MALLOCSEG;
  187.     mtr[mtrx].m_ptr.m_segh = Seg;
  188.     mtr[mtrx].m_cnt = Seg->alloc_count;
  189.     mtr[mtrx].m_size = SegSize;
  190.     mtr[mtrx++].m_optimseg = OptimumSeg;
  191. #endif
  192.     }
  193.     else {
  194.         Seg = Seg->next;
  195.         wSeg = HIWORD(Seg);
  196.     }
  197.         
  198.     if (Seg == OptimumSeg) continue;    /* skip this already tried
  199.                            one */
  200.     /*-try to allocate space in that segment */
  201. #if MEMTRACE
  202.         mtr[mtrx].m_cnt = Seg->alloc_count;
  203. #endif
  204.     Block = SubAlloc (wSeg, size);
  205.     if (Block != NULL) ++(Seg->alloc_count);
  206.     if ((Block != NULL) || NewSeg) {
  207.         OptimumSeg = Seg;   /* next malloc will try this segment
  208.                    first */
  209.         return (char*)Block;
  210.     }
  211.     }
  212. } /* malloc */
  213.  
  214. /* free:    frees an allocated block */
  215. /* =====                              */
  216.  
  217. void CDECL free (void *block)
  218. {
  219.     HANDLE  hSeg;
  220.     WORD    wSeg;
  221.     SEGHEADER *Seg;
  222.     HANDLE  hBlock;
  223. #if MEMTRACE
  224.     WORD    RealSize = 0;
  225. #endif
  226.  
  227.     if (FarStorage == FALSE) {  /* use the local heap */
  228.     HANDLE hMem;
  229.  
  230.     hMem = LocalHandle (LOWORD(block));
  231.     LocalUnlock (hMem);
  232.     LocalFree (hMem);
  233.     return;
  234.     }
  235.  
  236.     wSeg = HIWORD((DWORD)block);
  237.     hSeg = LOWORD(GlobalHandle (wSeg));
  238.  
  239.     SWITCH_DS(wSeg)
  240.     LocalUnlock (hBlock = LocalHandle (LOWORD(block)));
  241. #if MEMTRACE
  242.     RealSize = LocalSize (hBlock);
  243. #endif
  244.     LocalFree (hBlock);
  245.     RESTORE_DS
  246.  
  247.     Seg = (SEGHEADER *)(MAKELONG(SEGHEADOFFSET,HIWORD(block)));
  248. #if MEMTRACE
  249.     mtr[mtrx].m_func = MTR_FREE;
  250.     mtr[mtrx].m_ptr.m_block = block;
  251.     mtr[mtrx].m_cnt = Seg->alloc_count;
  252.     mtr[mtrx].m_size = RealSize;
  253.     mtr[mtrx++].m_optimseg = OptimumSeg;
  254. #endif
  255.     if (--(Seg->alloc_count) == 0) {  /* this segment is no longer used!
  256.                      Let's get rid of it */
  257.         SEGHEADER   *sp;
  258.  
  259.         if (Seg == OptimumSeg) OptimumSeg = NULL;
  260.         sp = &SegList;
  261.         while (sp->next != Seg) {
  262.             sp = sp->next;
  263.             if (sp == NULL) {   /* this segment is not in the list!!! */
  264.                 /* this should not happen, but you never know... */
  265.                 static BOOL WarningDisplayed = FALSE;
  266.  
  267.                 if (!WarningDisplayed) {
  268.             MessageBox (hFrameWnd,
  269.                                 "Please shutdown EMACS as soon as possible",
  270.                                 "Corrupted memory",
  271.                                 MB_OK | MB_ICONSTOP);
  272.                 }
  273.                 WarningDisplayed = TRUE;
  274.                 return;
  275.             }
  276.         }
  277.         sp->next = Seg->next;       /* unlink the segment */
  278. #if MEMTRACE
  279.         mtr[mtrx].m_func = MTR_FREESEG;
  280.         mtr[mtrx].m_ptr.m_segh = Seg;
  281.         mtr[mtrx].m_cnt = Seg->alloc_count;
  282.         mtr[mtrx].m_size = GlobalSize (hSeg);
  283.         mtr[mtrx++].m_optimseg = OptimumSeg;
  284. #endif
  285.  
  286.         SWITCH_DS(wSeg)
  287.     UnlockData (0);
  288.     RESTORE_DS
  289.     
  290.         GlobalUnlock (hSeg);
  291.         GlobalFree (hSeg);          /* and release it */
  292.     }
  293.     else {  /* segment still in use */
  294.     OptimumSeg = Seg;       /* next malloc will try this segment
  295.                    first */
  296.     }
  297. } /* free */
  298.  
  299. /* realloc: reallocates a chunk of memory (shrink or expand) */
  300. /* ========                                                   */
  301.  
  302. void * CDECL realloc(void * oldblock, size_t size);
  303. {
  304.     HANDLE  hBlock, hOldBlock;
  305.     void    *Block;
  306.     WORD    wSeg;
  307.     int     OldSize;
  308. #if MEMTRACE
  309.     WORD    RealSize = 0;
  310. #endif
  311.  
  312.     if (oldblock == NULL) return malloc (size);
  313.     
  314.     if (FarStorage == FALSE) {  /* use the local heap */
  315.     HANDLE hMem;
  316.  
  317.     hMem = LocalHandle (LOWORD(oldblock));
  318.     LocalUnlock (hMem);
  319.     if ((hMem = LocalReAlloc (hMem, LMEM_MOVEABLE, size)) != NULL) {
  320.         return (LPSTR)LocalLock (hMem);
  321.     }
  322.     else return NULL;
  323.     }
  324.  
  325.     wSeg = HIWORD(oldblock);
  326.  
  327.     SWITCH_DS(wSeg)
  328.     LocalUnlock (hOldBlock = LocalHandle (LOWORD(oldblock)));
  329.     OldSize = LocalSize (hOldBlock);
  330.     hBlock = LocalReAlloc (hOldBlock, size, LMEM_MOVEABLE | LMEM_NOCOMPACT);
  331.     if (hBlock) {
  332.     Block = (LPSTR)LocalLock (hBlock);
  333. #if MEMTRACE
  334.     RealSize = LocalSize (hBlock);
  335. #endif
  336.     }
  337.     else oldblock = LocalLock (hOldBlock); 
  338.     RESTORE_DS
  339. #if MEMTRACE
  340.     mtr[mtrx].m_func = MTR_REALLOC;
  341.     mtr[mtrx].m_ptr.m_block = hBlock ? Block : NULL;
  342.     mtr[mtrx].m_cnt = ((SEGHEADER *)(MAKELONG(SEGHEADOFFSET,wSeg)))->alloc_count;
  343.     mtr[mtrx].m_size = RealSize;
  344.     mtr[mtrx++].m_optimseg = OptimumSeg;
  345. #endif
  346.     
  347.     if (hBlock) return Block;
  348.     else {  /* we have to malloc, possibly into another segment, and
  349.            copy the data over */
  350.         if ((Block = malloc (size)) != NULL) {
  351.             _fmemcpy (Block, oldblock, min(size, OldSize));
  352.         free (oldblock);
  353.         }
  354.         return Block;
  355.     }
  356. } /* realloc */
  357. #endif  /* SUBALLOC */
  358.  
  359. /* InitializeFarStorage:    start the suballocation mechanism */
  360. /* ====================                                       */
  361.  
  362. void FAR PASCAL InitializeFarStorage (void)
  363. {
  364. #if SUBALLOC
  365.     FarStorage = TRUE;
  366. #endif
  367. } /* InitializeFarStorage */
  368.  
  369. /* JettisonFarStorage: Release all the global segments (quitting time) */
  370. /* ==================                                                  */
  371.  
  372. void FAR PASCAL JettisonFarStorage (void)
  373. {
  374. #if SUBALLOC
  375.     SEGHEADER   *sp;
  376.     HANDLE      hSeg;
  377.  
  378.     sp = SegList.next;
  379.     while (sp != NULL) {
  380.     hSeg = LOWORD(GlobalHandle (HIWORD((DWORD)sp)));
  381.     sp = sp->next;
  382.         GlobalUnlock (hSeg);
  383.         GlobalFree (hSeg);
  384.     }
  385.     FarStorage = FALSE;
  386. #endif
  387. } /* JettisonFarStorage */
  388.  
  389. #endif    /* WINDOW_MSWIN */
  390.  
  391.